#include <rtthread.h>

#include "spl06_01.h"
#include "spl06_api.h"
#define HW_ADR 0x77

#define ADC_DEV_NAME "spl06"
#define DBG_TAG "spl06"
#define DBG_LVL DBG_INFO

#include <rtdbg.h>
spi_dev_t spl_spi = {
    .cs_pin = SPL_CSN_PIN,
    .mode = RT_SPI_MODE_3 | RT_SPI_MSB,
    .data_width = 8,
    .max_hz = 20 * 1000 * 1000,
};
static int spl0601_get_calib_param(spl0601_t * hdev);
struct spl06_register_map spl06_regs = {0};

uint8_t spl06_spi_read(spl0601_t *hdev, uint8_t regadr, uint8_t *data, uint8_t len)
{
    /**
     * @brief Reading is done by lowering CSB and first sending one control byte.
     * The control bytes consist of the SPI register address (= full register address without bit 7)
     * and the read command (bit7=RW=’1’). After writing the control byte,
     * data is sent out of the SDO pin (SDA in 3-wire mode);
     * the register address is automatically incremented.
     *
     */
    regadr |= 0x80;
    // struct rt_spi_message msg1, msg2;
    // msg1.send_buf = &regadr;
    // msg1.recv_buf = RT_NULL;
    // msg1.length = 1;
    // msg1.cs_take = 1;
    // msg1.cs_release = 0;
    // msg1.next = &msg2;

    // msg2.send_buf = RT_NULL;
    // msg2.recv_buf = data;
    // msg2.length = len;
    // msg2.cs_take = 0;
    // msg2.cs_release = 1;
    // msg2.next = RT_NULL;
    // rt_spi_transfer_message(hdev->bus, &msg1);
    spi_send_then_receive(hdev->bus, &regadr, 1, data, len);
    return RT_EOK;
}
/**
 * @brief
 *
 * @param hdev
 * @param regadr
 * @param data
 * @param len
 * @return uint8_t
 */
uint8_t spl06_spi_write(spl0601_t *hdev, uint8_t regadr, uint8_t *data, uint8_t len)
{
    /**
     * @brief Writing is done by lowering CSB and sending pairs control bytes and register data.
     * The control bytes consist of the SPI register address (=full register address without bit 7)
     * and the write command (bit7=RW=’0’). Several pairs can be written without raising CSB.
     * The transaction is ended by a raising CSB.
     *
     */
    // regadr &= 0x7F;
    // struct rt_spi_message msg1, msg2;
    // msg1.send_buf = &regadr;
    // msg1.recv_buf = RT_NULL;
    // msg1.length = 1;
    // msg1.cs_take = 1;
    // msg1.cs_release = 0;
    // msg1.next = &msg2;

    // msg2.send_buf = data;
    // msg2.recv_buf = RT_NULL;
    // msg2.length = len;
    // msg2.cs_take = 1;
    // msg2.cs_release = 1;
    // msg2.next = RT_NULL;
    // rt_spi_transfer_message(hdev->bus, &msg1);
    spi_send_then_send(hdev->bus, &regadr, 1, data, len);
    return RT_EOK;
}

uint8_t spl06_write_reg(spl0601_t *hdev, uint8_t reg, uint8_t val)
{
    return spl06_spi_write(hdev, reg, &val, 1);
}
uint8_t spl06_read_reg(spl0601_t *hdev, uint8_t reg)
{
    uint8_t val;
    spl06_spi_read(hdev, reg, &val, 1);
    return val;
}


int spl0601_init(spl0601_t *hdev, const char *busname)
{

    hdev->bus = &spl_spi;

    if (hdev->bus == RT_NULL)
    {
        return -1;
    }
    hdev->i32rawPressure = 0;
    hdev->i32rawTemperature = 0;
    if (spl0601_get_calib_param(hdev) != RT_EOK)
    {
        return -1;
    }
    hdev->chip_id = spl06_read_reg(hdev, SPL0601_REG_ID);
    if (hdev->chip_id == 0x10)
    {
        LOG_I("Product and Revision ID: 0x%02X", hdev->chip_id);
    }
    else
    {
        LOG_E("Product and Revision ID error: 0x%02X", hdev->chip_id);
        return -1;
    }
    spl06_temperature_rate_set(hdev, PT_MEASUREMENT_RATE_4, PT_OVERSAMPLE_RATE_1);
    spl06_pressure_rate_set(hdev, PT_MEASUREMENT_RATE_4, PT_OVERSAMPLE_RATE_64);

    return 0;
}

const int32_t OversamplingRateScaleFactor_kT_kT[8] = {
    524288,  // 1 (single)
    1572864, // 2 times (Low Power)
    3670016, // 4 times
    7864320, // 8 times
    253952,  // 16 times (Standard)
    516096,  // 32 times
    1040384, // 64 times (High Precision)
    2088960, // 128 times
};
/**
 * @brief set pressure measurement rate and oversample rate
 *
 * @param hdev
 * @param pm measurement rate
 * @param prc oversample rate
 */
void spl06_pressure_rate_set(spl0601_t *hdev, enum spl06_measurement_rate pm, enum spl06_oversample_rate prc)
{
    if (pm <= PT_MEASUREMENT_RATE_128)
    {
        spl06_regs.prs_cfg_bit.PM_RATE = pm;
    }
    if (prc <= PT_OVERSAMPLE_RATE_128)
    {
        hdev->i32kP = OversamplingRateScaleFactor_kT_kT[prc];
        spl06_regs.prs_cfg_bit.PM_PRC = prc;
        if (prc > PT_OVERSAMPLE_RATE_8)
        {
            spl06_regs.cfg_reg_bit.P_SHIFT = 1;
        }else
        {

        }
    }
    LOG_I("PRS_CFG:%02X, CFG_REG:%02X, i32kP:%d,", spl06_regs.PRS_CFG, spl06_regs.CFG_REG, hdev->i32kP);
    spl06_write_reg(hdev, SPL0601_REG_PRS_CFG, spl06_regs.PRS_CFG);
    spl06_write_reg(hdev, SPL0601_REG_CFG_REG, spl06_regs.CFG_REG);
    LOG_I("rPRS_CFG:%02X", spl06_read_reg(hdev, SPL0601_REG_PRS_CFG));
}
/**
 * @brief set temperature measurement rate and oversample rate
 *
 * @param hdev
 * @param pm measurement rate
 * @param prc oversample rate
 */
void spl06_temperature_rate_set(spl0601_t *hdev, enum spl06_measurement_rate pm, enum spl06_oversample_rate prc)
{
    if (pm <= PT_MEASUREMENT_RATE_128)
    {
        spl06_regs.tmp_cfg_bit.PM_RATE = pm;
        spl06_regs.tmp_cfg_bit.TMP_EX = 1; // NOTE 温度不对时，必须要用这个！！！
    }
    if (prc <= PT_OVERSAMPLE_RATE_128)
    {
        hdev->i32kT = OversamplingRateScaleFactor_kT_kT[prc];
        spl06_regs.tmp_cfg_bit.PM_PRC = prc;
        if (prc > PT_OVERSAMPLE_RATE_8)
        {
            spl06_regs.cfg_reg_bit.T_SHIFT = 1;
        }
    }
    LOG_D("TMP_CFG:%02X, CFG_REG:%02X, i32kT:%d,", spl06_regs.TMP_CFG, spl06_regs.CFG_REG, hdev->i32kT);
    spl06_write_reg(hdev, SPL0601_REG_TMP_CFG, spl06_regs.TMP_CFG);
    spl06_write_reg(hdev, SPL0601_REG_CFG_REG, spl06_regs.CFG_REG);
    LOG_D("rTMP_CFG:%02X", spl06_read_reg(hdev, SPL0601_REG_TMP_CFG));
}

static int spl0601_get_calib_param(spl0601_t *hdev)
{
    // NOTE 结构体直接接收处理COEF数据流！！！
    uint8_t raw[20] = {0};
    uint8_t i = 0;
    while (1)
    {
        spl06_regs.MEAS_CFG = spl06_read_reg(hdev, SPL0601_REG_MEAS_CFG);
        if (spl06_regs.meas_cfg_bit.COEF_RDY && (spl06_regs.MEAS_CFG != 0xFF))
        {
            break;
        }
        // LOG_W("waiting for coef ready %02X...",spl06_regs.MEAS_CFG);
        if (i++ > 5)
        {
            LOG_E("SPL06 ERROR, waiting for coef ready timeout!");
            return -RT_EOK;
        }
        rt_thread_delay(10);
    }

    spl06_spi_read(hdev, SPL0601_REG_COEF, raw, 18);
    // union spl06_coef coef = { 0 };
    LOG_D("Raw: ");
    for (int i = 0; i < 18; i++) // NOTE 大小数据端重新对齐一下
    {
        // rt_kprintf("%02X ",raw[i]);
        hdev->calib_param.coef[i] = raw[17 - i];
    }
    LOG_D("\ncoef: \n");
    LOG_D("c0: 0x%08X, %d\n", hdev->calib_param.c0, hdev->calib_param.c0);
    LOG_D("c1: 0x%08X, %d\n", hdev->calib_param.c1, hdev->calib_param.c1);
    LOG_D("c00:0x%08X, %d\n", hdev->calib_param.c00, hdev->calib_param.c00);
    LOG_D("c10:0x%08X, %d\n", hdev->calib_param.c10, hdev->calib_param.c10);
    LOG_D("c01:0x%08X, %d\n", hdev->calib_param.c01, hdev->calib_param.c01);
    LOG_D("c11:0x%08X, %d\n", hdev->calib_param.c11, hdev->calib_param.c11);
    LOG_D("c20:0x%08X, %d\n", hdev->calib_param.c20, hdev->calib_param.c20);
    LOG_D("c21:0x%08X, %d\n", hdev->calib_param.c21, hdev->calib_param.c21);
    LOG_D("c30:0x%08X, %d\n", hdev->calib_param.c30, hdev->calib_param.c30);
    hdev->calib_param.c0 = hdev->calib_param.c0;
    hdev->calib_param.c1 = hdev->calib_param.c1;
    hdev->calib_param.c00 = hdev->calib_param.c00;
    hdev->calib_param.c10 = hdev->calib_param.c10;
    hdev->calib_param.c01 = hdev->calib_param.c01;
    hdev->calib_param.c11 = hdev->calib_param.c11;
    hdev->calib_param.c20 = hdev->calib_param.c20;
    hdev->calib_param.c21 = hdev->calib_param.c21;
    hdev->calib_param.c30 = hdev->calib_param.c30;
    return RT_EOK;
}

void spl0601_start_temperature(spl0601_t *hdev)
{
    spl06_regs.MEAS_CFG = 0;
    spl06_regs.meas_cfg_bit.MEAS_CTRL = MEAS_CTRL_TEMPERATURE_MEASUREMENT;
    LOG_D("MEAS_CFG(%02X):%02X", SPL0601_REG_MEAS_CFG, spl06_regs.MEAS_CFG);
    spl06_write_reg(hdev, SPL0601_REG_MEAS_CFG, spl06_regs.MEAS_CFG);
}

void spl0601_start_pressure(spl0601_t *hdev)
{
    spl06_regs.MEAS_CFG = 0;
    spl06_regs.meas_cfg_bit.MEAS_CTRL = MEAS_CTRL_PRESSURE_MEASUREMENT;
    LOG_D("MEAS_CFG(%02X):%02X", SPL0601_REG_MEAS_CFG, spl06_regs.MEAS_CFG);
    spl06_write_reg(hdev, SPL0601_REG_MEAS_CFG, spl06_regs.MEAS_CFG);
}

void spl0601_start_continuous(spl0601_t *hdev, uint8_t mode)
{
    spl06_regs.MEAS_CFG = 0;
    spl06_regs.meas_cfg_bit.MEAS_CTRL = mode;
    LOG_D("regs:%d reg:%d %d\n", sizeof(spl06_regs), sizeof(spl06_regs.MEAS_CFG), spl06_regs.MEAS_CFG);
    spl06_spi_write(hdev, SPL0601_REG_MEAS_CFG, &spl06_regs.MEAS_CFG, 1);
    // switch(mode)
    // {
    //     case SPL06_MODE_WEATHER_STATION:
    //     spl06_pressure_rate_set(hdev,PT_MEASUREMENT_RATE_2,PT_OVERSAMPLE_RATE_1);
    //     spl06_temperature_rate_set(hdev,PT_MEASUREMENT_RATE_1,PT_OVERSAMPLE_RATE_1);
    //     break;
    //     case SPL06_MODE_INDOOR_NAVIGATION:
    //     spl06_pressure_rate_set(hdev,PT_MEASUREMENT_RATE_2,PT_OVERSAMPLE_RATE_16);
    //     spl06_temperature_rate_set(hdev,PT_MEASUREMENT_RATE_1,PT_OVERSAMPLE_RATE_1);
    //     break;
    //     case SPL06_MODE_SPORTS:
    //     spl06_pressure_rate_set(hdev,PT_MEASUREMENT_RATE_4,PT_OVERSAMPLE_RATE_64);
    //     spl06_temperature_rate_set(hdev,PT_MEASUREMENT_RATE_4,PT_OVERSAMPLE_RATE_1);
    //     break;
    //     default:
    //     spl06_pressure_rate_set(hdev,PT_MEASUREMENT_RATE_4,PT_OVERSAMPLE_RATE_64);
    //     spl06_temperature_rate_set(hdev,PT_MEASUREMENT_RATE_4,PT_OVERSAMPLE_RATE_1);
    //     break;
    // }
}

void spl0601_stop(spl0601_t *hdev)
{
    spl06_regs.MEAS_CFG = 0;
    spl06_regs.meas_cfg_bit.MEAS_CTRL = MEAS_CTRL_STOP;
    LOG_D("regs:%d reg:%d %d\n", sizeof(spl06_regs), sizeof(spl06_regs.MEAS_CFG), spl06_regs.MEAS_CFG);
    spl06_spi_write(hdev, SPL0601_REG_MEAS_CFG, &spl06_regs.MEAS_CFG, 1);
}

void spl0601_get_raw_temp(spl0601_t *hdev)
{
    uint8_t buf[3];

    spl06_spi_read(hdev, SPL0601_REG_TMP_B2, buf, 3);

    hdev->i32rawTemperature = (int32_t)buf[0] << 16 | (int32_t)buf[1] << 8 | (int32_t)buf[2];
    hdev->i32rawTemperature = (hdev->i32rawTemperature & 0x800000) ? (0xFF000000 | hdev->i32rawTemperature) : hdev->i32rawTemperature;
    LOG_D("i32rawTemperature:%d", hdev->i32rawTemperature);
}

void spl0601_get_raw_pressure(spl0601_t *hdev)
{
    uint8_t buf[3];
    spl06_spi_read(hdev, SPL0601_REG_PRS_B2, buf, 3);
    hdev->i32rawPressure = (int32_t)buf[0] << 16 | (int32_t)buf[1] << 8 | (int32_t)buf[2];
    hdev->i32rawPressure = (hdev->i32rawPressure & 0x800000) ? (0xFF000000 | hdev->i32rawPressure) : hdev->i32rawPressure;
    LOG_D("raw pressure = %d, %08X", hdev->i32rawPressure, hdev->i32rawPressure);
}

float spl0601_get_temperature(spl0601_t *hdev)
{
    float fTCompensate;
    float Traw_sc;

    Traw_sc = (float)hdev->i32rawTemperature / (float)hdev->i32kT;
    fTCompensate = hdev->calib_param.c0 * 0.5f + hdev->calib_param.c1 * Traw_sc;
    return fTCompensate;
}
float spl0601_get_pressure(spl0601_t *hdev)
{
    float fTsc, fPsc;
    float qua2, qua3;
    float fPCompensate;

    fTsc = hdev->i32rawTemperature / (float)hdev->i32kT;
    fPsc = hdev->i32rawPressure / (float)hdev->i32kP;
    qua2 = hdev->calib_param.c10 + fPsc * (hdev->calib_param.c20 + fPsc * hdev->calib_param.c30);
    qua3 = fTsc * fPsc * (hdev->calib_param.c11 + fPsc * hdev->calib_param.c21);

    fPCompensate = hdev->calib_param.c00 + fPsc * qua2 + fTsc * hdev->calib_param.c01 + qua3;
    return fPCompensate;
}
